// {{ .Data.GenerateTitle }}
package main

import (
	"fmt"
	_ "{{ .PkgName }}/service"
	"gitee.com/kristas/booting-go/framework/core/bean"
	"gitee.com/kristas/booting-go/framework/core/ioc/bean_factory"
	"gitee.com/kristas/booting-go/framework/core/ioc/bean_repository"
	"gitee.com/kristas/booting-go/framework/core/statement"
	"gitee.com/kristas/booting-go/framework/core/statement/types"
	"gitee.com/kristas/booting-go/gen_tool/booctl/creator"
	"gitee.com/kristas/booting-go/gen_tool/booctl/util"
	"os"
	"path/filepath"
	"sort"
)

type ServiceGenerator struct {
	types.Component
	lock      *WdLock
	root      string
	Services  []statement.Service `wire:""`
	beanNames []string
	layer     string
	cmd       util.GoCmd
}

func (s *ServiceGenerator) Order() int {
	return 1
}

func (s *ServiceGenerator) Async() bool {
	return false
}

func NewServiceGenerator(lock *WdLock) *ServiceGenerator {
	return &ServiceGenerator{lock: lock}
}

func (s *ServiceGenerator) Init() error {
	s.root = s.lock.RequiredRoot()
	defer s.lock.Release()
	err := os.Chdir(s.root)
	if err != nil {
		return err
	}
	s.layer = "service"
	for i := range s.Services {
		repo := s.Services[i]
		s.beanNames = append(s.beanNames, util.GetBeanStructName(repo))
	}
	sort.Slice(s.beanNames, func(i, j int) bool {
		return s.beanNames[i] < s.beanNames[j]
	})
	return s.Create()
}

func (s *ServiceGenerator) Create() error {
	defer s.cmd.Fmt()
    g := creator.NewGoFile("common_factory", s.layer, s.layer+"_factory", false)
	g.SetAttribute("Beans", s.beanNames)
	g.SetAttribute("Package", s.layer)
	err := g.Create()
	if err != nil {
		return err
	}
	return nil
}

func (s *ServiceGenerator) Filter(bean bean.Bean) bool {
	_, ok := bean.(statement.Service)
	return ok
}

func (s *ServiceGenerator) Do(bean bean.Bean) error {
	s.root = s.lock.RequiredRoot()
	defer s.lock.Release()
	err := os.Chdir(s.root)
	svc := bean.(statement.Service)
	if err != nil {
		return err
	}
	svcFileName := filepath.Join(s.root, "service", util.GetBeanFileName(bean))
	err = s.GenerateRepositoryFactory(svc, svcFileName)
	if err != nil {
		return err
	}
	s.cmd.Fmt(svcFileName)
	return nil
}

func (s *ServiceGenerator) GenerateRepositoryFactory(svc statement.Service, svcFileName string) error {
	singleton := bean_repository.GetSingleton("repository_factory")
	if singleton == nil {
		return nil
	}
	factoryTag := fmt.Sprintf(`%s:"repository_factory"`, bean_factory.InjectFieldTag)
	contains, err := util.IsFileContains(factoryTag, func(mode int) (*os.File, error) {
		return util.OpenFile(svcFileName, mode)
	})
	if err != nil {
		return err
	}
	if contains {
		return nil
	}
	t := fmt.Sprintf("repository.Factory `%s`", factoryTag)
	serviceTag := fmt.Sprintf("`service:\"%s\"`", svc.ServiceFor())
	err = util.ReplaceFileContents(serviceTag, fmt.Sprintf("%s\n%s", serviceTag, t), 1, func(mode int) (*os.File, error) {
		return util.OpenFile(svcFileName, mode)
	})
	if err != nil {
		return err
	}
	imports := util.BuildImport("repository")
	err = util.WriteImports(svcFileName, []string{imports})
	if err != nil {
		return err
	}
	return nil
}
